#ifndef LEX_H
#define LEX_H
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

typedef enum
{
    LEX_NULL,
    LEX_STRING_DECL,
    LEX_INT_DECL,
    LEX_BOOL_DECL,
    LEX_AND,
    LEX_NOT,
    LEX_OR,
    LEX_FALSE,
    LEX_TRUE,
    LEX_BEGIN, //{ bracket
    LEX_BOOL,
    LEX_DO,
    LEX_END, // } bracket
    LEX_ELSE,
    LEX_IF,
    LEX_INT,
    LEX_REAL,
    LEX_PROGRAM,
    LEX_READ,
    LEX_WRITE,
    LEX_STRING,
    LEX_FOR,
    LEX_WHILE,

    LEX_FIN,
    LEX_SEMICOLON,
    LEX_COMMA,
    LEX_COLON,
    LEX_ASSIGN,
    LEX_EQ,
    LEX_LESS,
    LEX_GREATER,
    LEX_PLUS,
    LEX_MINUS,
    LEX_TIMES,
    LEX_SLASH,
    LEX_PLUS_ASSIGN,
    LEX_MINUS_ASSIGN,
    LEX_TIMES_ASSIGN,
    LEX_SLASH_ASSIGN,
    LEX_MOD,
    LEX_MOD_ASSIGN,

    LEX_NEQ,
    LEX_GEQ,
    LEX_LEQ,
    LEX_IDENT,
    LEX_NUM,
    LEX_LPAREN,
    LEX_RPAREN,
    LEX_CONTINUE,
    LEX_UNARY_PLUS,
    LEX_UNARY_MINUS,


    POLIZ_POP,
    POLIZ_ARGSBEGIN,
    POLIZ_ADDR,
    POLIZ_JMP,
    POLIZ_LABEL,
    POLIZ_FJMP

} lex_type_t;

typedef struct {
    union {
        string *s_value;
        int i_value;
        bool b_value;
        float f_value;
        void *v_value;
    } val;
    lex_type_t type;

}value_t;

inline string sfromint(int x)
{
    stringstream out;
    out << x;
    return out.str();
}

class lex
{
    lex_type_t m_type;
    int m_val;
public:
    lex(lex_type_t lt = LEX_NULL, int val = 0) {
        m_type = lt;
        m_val = val;
    }


    lex_type_t get_type() const {
        return m_type;
    }
    int get_val() const {
        return m_val;
    }

    void set_value(int val) {
        m_val = val;
    }

    void set_type(lex_type_t type) {
        m_type = type;
    }

    string to_string() const {
        switch (m_type) {
        case LEX_BOOL:
            if (m_val) {
                return  "(true)";
            } else {
                return "(false)";
            }
            break;
        default:
            return "(LEX_TYPE == " + sfromint(m_type) + " LEX_VAL == " + sfromint(m_val) + ")";
        }
    }

    friend  ostream& operator << (ostream &p, const lex &l) {
        p << l.to_string() << endl;
        return p;
    }
    ~lex() {
    }
};

#endif // LEX_H
